
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "frame.h"
#include "log.h"
#include "debug.h"

Frame_t * frame_create() {
	Frame_t * frame = ( Frame_t * ) malloc( sizeof( Frame_t ) );
	if ( !frame ) return NULL;

	memset( frame, 0, sizeof(Frame_t) );
	frame->content = NULL;

	return frame;
}


void frame_destroy( Frame_t * frame ) {
	if ( frame->content ) 
		free( frame->content );

	if ( frame )
		free( frame );
}

int frame_recv( Frame_t * frame, int sockfd ) {
	int len;
	Frame_hdr_t hdr;

	len = recv( sockfd, &hdr, sizeof(Frame_hdr_t), 0);
	if (len < 0 ) goto error;

	if ( len == sizeof(Frame_hdr_t) ) {
		frame->type = ntohs( hdr.type );	
		frame->size = ntohs( hdr.size );
		frame->seq = ntohl( hdr.seq );
		frame->ack = ntohl( hdr.ack );
	} else {
		// incomplete frame or error
		pDEBUG("Incomplete frame or error");
		notimplemented();
	}

	pDEBUG("Received frame\n");
	bufferDEBUG( &hdr );
	frame_display( frame );

	return 0;

error:
	return -1;
}

int frame_send( Frame_t * frame, int sockfd ) {
	Frame_hdr_t hdr;
	int len;

	hdr.type = htons( frame->type );
	hdr.size = htons( frame->size );
	hdr.seq = htonl( frame->seq );
	hdr.ack = htonl( frame->ack );
	
	pDEBUG("Sending frame\n");
	frame_display( frame );
	len = send( sockfd, &hdr, sizeof(hdr), 0 );
	if ( len < 0 ) goto error;


	return 0;

error:
	return -1;
}

char * frame_type_str( unsigned short type ) {
	char * result = NULL;
	switch ( type ) {
		case FRAME_TYPE_AUTH: 
			result = "auth";
			break;
		case FRAME_TYPE_CONTROL:
			result = "control";
			break;
		case FRAME_TYPE_MESSAGE:
			result = "message";
			break;
		default:
			result = "undefined";
			break;
	}
	return result;
}

char * frame_auth_type_str( unsigned short type ) {
	char * result = NULL;
	switch ( type ) {
		case FRAME_AUTH_TYPE_HELLO:
			result = "hello";
			break;
		case FRAME_AUTH_TYPE_TOKEN:
			result = "token";
			break;
		case FRAME_AUTH_TYPE_ACCEPT:
			result = "accept";
			break;
		case FRAME_AUTH_TYPE_DENY:
			result = "deny";
		default:
			result = "undefined";
			break;
		}
	return result;
}

void frame_display( Frame_t * frame ) {

	char * frame_type = NULL;

	if ( ! frame ) 
	{ 
		log_error( "NULL FRAME!\n" );
		return ;
	}

	frame_type = frame_type_str( frame->type );

	printf( " * Frame:\n" );
	printf( "  * type : %s ( %d )\n", frame_type, frame->type );
	printf( "  * size : %d\n", frame->size );
	printf( "  * seq :  %ld\n", frame->seq );
	printf( "  * ack : %ld\n", frame->ack ); 
}

Frame_t * frame_get( Frame_t ** framelist )
{
	Frame_t * result;

	result = NULL;
	if ( *framelist )
	{
		result = *framelist;
		*framelist = result->next;
		result->next = NULL;
	}

	return result;
}

int frame_put( Frame_t ** framelist, Frame_t * frame )
{
	Frame_t * tmp, * prev;

	prev = NULL;
	tmp = *framelist;

	frame->next = NULL;

	while( tmp )
	{
		prev = tmp;
		tmp = tmp->next;
	}

	if (prev)
		prev->next = frame;
	else
		*framelist = frame;

	return 0;
}


int protocol_frame_is_pending( Frame_t ** framelist ) 
{
	if ( *framelist ) 
		return 1;
	else
		return 0;
}
